<template>
  <div class="wrapper">
    <el-tabs>
        <el-tab-pane label="常规加分项">
            <el-table :data="dkpRecord.raiseItem" size="mini" border stripe style="width: 100%">
                <el-table-column prop="name" label="Boss名称" width="120"></el-table-column>
                <el-table-column prop="name" label="加分值" width="120">
                    <template slot-scope="scope">
                        <el-input-number v-model="scope.row.score" size="mini" class="score-input" :min="0" @change="bossScoreChange($event,scope.row)"></el-input-number>
                        <div><el-checkbox v-model="scope.row.checkAll" @change="checkAllChange($event,scope.row)">{{scope.row.checkAll?'取消全选':'全选'}}</el-checkbox></div>
                    </template>
                </el-table-column>
                <el-table-column prop="time" label="击杀时间" width="140"></el-table-column>
                <el-table-column prop="players" label="参与人员(名字为灰色表示当时可能不在团，默认不加分，可根据实际情况修改)">
                    <template slot-scope="scope">
                        <div class="players-wrapper with-checkbox">
                            <span v-for="player in scope.row.players" :key="player.name">
                                <el-tooltip placement="top" effect="dark" :content="'这是小号，'+{'mo':'大号在团时，小号不加分','oso':'只有一个小号能加分','':''}[player.noScoreReason]" :disabled="!player.noScore">
                                <span class="player-name" :style="{color: player.isOnLine?classMap[player.class]:'#7d7d7a'}">{{player.name}}</span>
                                </el-tooltip>
                                <el-checkbox v-model="player.checked" :disabled="player.noScore" label=""></el-checkbox>
                                <el-input-number 
                                    v-model="player.score" 
                                    :min="0"
                                    :disabled="player.noScore"
                                    class="score-input" 
                                    size="mini" placeholder=""></el-input-number>
                            </span>
                        </div>
                    </template>
                </el-table-column>
            </el-table>
        </el-tab-pane>
        <el-tab-pane label="额外加分项">
            <el-table :data="dkpRecord.additionalRaiseItem" size="mini" border stripe style="width: 100%">
                <el-table-column prop="reason" label="加分类型" width="120">
                    <template slot-scope="scope">
                        <div>{{reasonMap[scope.row.reason]}}</div>
                        <el-button type="danger" size="mini" @click="removeRow(scope.row,'Raise')">删除</el-button>
                        <div><el-checkbox v-model="scope.row.checkAll" @change="checkAllChange($event,scope.row)">{{scope.row.checkAll?'取消全选':'全选'}}</el-checkbox></div>
                        <div v-if="scope.row.reason == 'other'">
                            <el-input type="textarea" size="mini" v-model="scope.row.reasonNote" placeholder="加分原因"></el-input>
                        </div>
                    </template>
                </el-table-column>
                <el-table-column prop="name" label="分值" width="120">
                    <template slot-scope="scope">
                        <el-input-number v-model="scope.row.score" size="mini" class="score-input" :min="0" @change="bossScoreChange($event,scope.row)"></el-input-number>
                    </template>
                </el-table-column>
                <el-table-column prop="players" label="参与人员">
                    <template slot="header" slot-scope="scope">
                        <el-dropdown @command="newAdditional($event,'Raise')">
                        <el-button type="primary" size="mini">
                            增加加分项<i class="el-icon-arrow-down el-icon--right"></i>
                        </el-button>
                        <el-dropdown-menu slot="dropdown">
                            <el-dropdown-item command="collect">集合分</el-dropdown-item>
                            <el-dropdown-item command="dismiss">解散分</el-dropdown-item>
                            <el-dropdown-item command="assart">开荒分</el-dropdown-item>
                            <el-dropdown-item command="firstDown">Boss首次击杀</el-dropdown-item>
                            <el-dropdown-item command="item">掉落装备得分</el-dropdown-item>
                            <el-dropdown-item command="whole">全程参与补助</el-dropdown-item>
                            <el-dropdown-item command="other">其他加分项</el-dropdown-item>
                        </el-dropdown-menu>
                        </el-dropdown>
                    </template>
                    <template slot-scope="scope">
                        <div class="players-wrapper with-checkbox">
                            <span v-for="player in scope.row.players" :key="player.name">
                                <el-tooltip placement="top" effect="dark" :content="'这是小号，'+{'mo':'大号在团时，小号不加分','oso':'只有一个小号能加分','':''}[player.noScoreReason]" :disabled="!player.noScore">
                                <span class="player-name" :style="{color: player.isOnLine?classMap[player.class]:'#7d7d7a'}">{{player.name}}</span>
                                </el-tooltip>
                                <el-checkbox v-model="player.checked" :disabled="player.noScore" label=""></el-checkbox>                              
                                <el-input-number 
                                    v-model="player.score" 
                                    :min="0"
                                    :disabled="player.noScore"
                                    class="score-input" 
                                    size="mini" placeholder=""></el-input-number>
                            </span>
                        </div>
                    </template>
                </el-table-column>
            </el-table>
        </el-tab-pane>
        <el-tab-pane label="常规扣分项">
            <el-table :data="dkpRecord.downItem" size="mini" border stripe style="width: 100%">
                <el-table-column prop="boss" label="Boss" width="160" align="center"></el-table-column>
                <el-table-column prop="itemName" label="装备名称" width="300" align="center">
                    <template slot-scope="scope">
                      <span v-if="!scope.row.itemID" :style="{color:scope.row.color}">{{scope.row.itemName}}</span>
                      <item-pop v-else :item-name="scope.row.itemName" :item-color="scope.row.color" :item-id="scope.row.itemID"></item-pop>
                    </template>
                </el-table-column>
                <el-table-column prop="costs" label="分值" width="140" align="center">
                    <template slot-scope="scope">
                        <el-input-number 
                            v-model="scope.row.player.score" 
                            :min="0"
                            class="score-input" 
                            size="mini" placeholder=""></el-input-number>
                    </template>
                </el-table-column>
                <el-table-column prop="player" label="拾取人员">
                    <template slot-scope="scope">
                        <span class="">
                            <span class="single-player-name" :style="{color: classMap[scope.row.player.class]}">{{scope.row.player.name}}</span>
                        </span>
                    </template>
                </el-table-column>
            </el-table>
        </el-tab-pane>
        <el-tab-pane label="额外扣分项">
            <el-table :data="dkpRecord.additionalDownItem" size="mini" border stripe style="width: 100%">
                <el-table-column prop="reason" label="加分类型" width="120">
                    <template slot-scope="scope">
                        <div>{{reasonMap[scope.row.reason]}}</div>
                        <el-button type="danger" size="mini" @click="removeRow(scope.row,'Down')">删除</el-button>
                        <div><el-checkbox v-model="scope.row.checkAll" @change="checkAllChange($event,scope.row)">{{scope.row.checkAll?'取消全选':'全选'}}</el-checkbox></div>
                        <div v-if="scope.row.reason == 'other'">
                            <el-input type="textarea" size="mini" v-model="scope.row.reasonNote" placeholder="扣分原因"></el-input>
                        </div>
                    </template>
                </el-table-column>
                <el-table-column prop="name" label="分值" width="120">
                    <template slot-scope="scope">
                        <el-input-number v-model="scope.row.score" size="mini" class="score-input" :min="0" @change="bossScoreChange($event,scope.row)"></el-input-number>
                    </template>
                </el-table-column>
                <el-table-column prop="players" label="参与人员">
                    <template slot="header" slot-scope="scope">
                        <el-dropdown @command="newAdditional($event,'Down')">
                        <el-button type="primary" size="mini">
                            增加扣分项<i class="el-icon-arrow-down el-icon--right"></i>
                        </el-button>
                        <el-dropdown-menu slot="dropdown">
                            <el-dropdown-item command="loot">获取装备</el-dropdown-item>
                            <el-dropdown-item command="add">引怪导致团灭</el-dropdown-item>
                            <el-dropdown-item command="ot">OT导致团灭</el-dropdown-item>
                            <el-dropdown-item command="disobey">不听指挥</el-dropdown-item>
                            <el-dropdown-item command="other">其他扣分项</el-dropdown-item>
                        </el-dropdown-menu>
                        </el-dropdown>
                    </template>
                    <template slot-scope="scope">
                        <div class="players-wrapper with-checkbox">
                            <span v-for="player in scope.row.players" :key="player.name">
                                <span class="player-name" :style="{color: classMap[player.class]}">{{player.name}}</span>
                                <el-checkbox v-model="player.checked" label=""></el-checkbox>                              
                                <el-input-number 
                                    v-model="player.score" 
                                    :min="0"
                                    class="score-input" 
                                    size="mini" placeholder=""></el-input-number>
                            </span>
                        </div>
                    </template>
                </el-table-column>
            </el-table>
        </el-tab-pane>
    </el-tabs>
  </div>
</template>

<script>
function dateFormat(v) {
  let dt = new Date(v);
  return (
    dt.getFullYear() +
    "-" +
    ("0" + (dt.getMonth() + 1)).slice(-2) +
    "-" +
    ("0" + dt.getDate()).slice(-2) +
    " " +
    ("0" + dt.getHours()).slice(-2) +
    ":" +
    ("0" + dt.getMinutes()).slice(-2) +
    ":" +
    ("0" + dt.getSeconds()).slice(-2)
  );
}

import ItemPop from '@/components/ItemPop'
export default {
  components: {ItemPop},
  props: {
    dkpObj: {
      required: true,
      type: Object
    }
  },
  data() {
    return {
      classMap: {
        战士: "#c2b396",
        盗贼: "#e4ff95",
        法师: "#4ee0ff",
        牧师: "#fbfbff",
        萨满祭司: "#f793d9",
        术士: "#6b75ee",
        德鲁伊: "#f99645",
        猎人: "#8ac37e"
      },
      reasonMap: {
        boss: "击杀boss得分",
        item: "掉落装备得分",
        collect: "集合分",
        dismiss: "解散分",
        assart: "开荒分",
        whole: "全程参与补助",
        firstDown: "Boss首次击杀",
        loot: "获取装备",
        add: "引怪导致团灭",
        ot: "OT导致团灭",
        disobey: "不听指挥",
        other: "其他"
      }
    };
  },
  computed: {
    dkpRecord() {
      let rec = {};
      rec.raiseItem = this.dkpObj.bossKills.map(o => {
        let score = 1;
        let players = this.getActivePlayers(score, o.time);
        let checkCount = 0, allCount = 0;
        players.forEach(o => {
          checkCount += o.checked;
          allCount += !o.noScore;
        });

        return {
          score,
          ...o,
          checkAll: checkCount == allCount,
          players
        };
      });

      rec.additionalRaiseItem = [];

      rec.downItem = this.dkpObj.loot
        .filter(o => o.costs && o.costs > 0)
        .map(o => {
          let player = this.dkpObj.playerRelation[o.player];
          let obj = {
            ...o,
            color: o.color,
            player: {
              name: o.player,
              class: player.class,
              score: o.costs
            }
          };

          return obj;
        });
      
      rec.additionalDownItem = [];
      return rec;
    },
    players() {
      return Object.keys(this.dkpObj.players);
    }
  },
  methods: {
    appendPlayer(player) {
      if(!this.dkpObj.players[player.name]){
        this.dkpObj.players[player.name] = {
          join: [],
          leave: []
        }

        this.dkpRecord.raiseItem.forEach(item=>{
          item.players.push({
            ...player,
            isOnLine: false,
            checked: false,
            noScore: false,
            noScoreReason: '',
            score: 0
          })
        })
        this.dkpRecord.additionalRaiseItem.forEach(item=>{
          item.players.push({
            ...player,
            isOnLine: false,
            checked: false,
            noScore: false,
            noScoreReason: '',
            score: 0
          })
        })
        this.dkpRecord.additionalDownItem.forEach(item=>{
          item.players.push({
            ...player,
            isOnLine: false,
            checked: false,
            noScore: false,
            noScoreReason: '',
            score: 0
          })
        })
      }
    },
    getActivePlayers(commonScore, time) {
      let players = [];

      Object.keys(this.dkpObj.players).forEach(p => {
        let player = this.dkpObj.playerRelation[p];
        let noScore = false;
        let isOnLine = true;
        let noScoreReason = '';
        let checked = false;
        let score = commonScore;

        if(time){
          isOnLine = this.isOnLine(p, time);
        }

        if (player.linkedTo) {//当前角色时小号
          if (Object.keys(this.dkpObj.players).some(n => n == player.linkedTo)) {
            //如果该角色绑定的大号在团，该小号不加分
            noScore = true;
            score = 0;
            checked = false;
            noScoreReason = 'mo' //大号在团（master online)
          } else if (players.some(m => m.linkedTo == player.linkedTo && !m.noScore && m.score > 0)) {
            //如果该角色绑定的大号，有其他小号在团，并且有分数
            noScore = true;
            checked = false;
            score = 0;
            noScoreReason = 'oso' //另有小号在团（other slave online）
          } else {
            score = isOnLine?commonScore:0;
            checked = isOnLine;
            noScore = false;
            noScoreReason = '';
          }
        } else {//大号根据是否在团判断计分
          if(time && !isOnLine){
            //如果大号当时没在团，判断该大号的小号该时间节点是否有在团，如果有，也算该大号在团
            isOnLine = this.isAttend(p, time)
          }
          checked = isOnLine;
          score = isOnLine?commonScore:0;
          noScore = false;
          noScoreReason = '';
        }

        players.push({
          name: p,
          race: player.race,
          class: player.class,
          linkedTo: player.linkedTo,
          isOnLine,
          checked,
          noScore,
          noScoreReason,
          score
        });
      });
      return players.sort((a, b) => b.isOnLine - a.isOnLine);
    },
    checkAllChange(value, row) {
      row.players.forEach(p=>{
        if(!p.noScore){
          p.checked = value;        
        }
      })
    },
    bossScoreChange(v, row) {
      row.players.filter(o => !o.noScore && o.checked).forEach(player => {
        player.score = v;
      });
    },
    isOnLine(name, time) {
      time = new Date(time);
      let player = this.dkpObj.players[name]
      if(!player){//不在队员列表中的肯定当时没在团
        return false
      }

      let { join, leave } = player;
      if (
        join.some(t => t < time) &&
        (leave.length == 0 || leave.every(t => t > time))
      ) {
        //boss击杀时间点之前进队，并且没有离队记录的，算当时在线
        return true;
      } else {
        //如果有离队记录，需要看boss击杀时间点之前的最后一次离队记录之后，是否有入队记录，如果有，则代表boss击杀时在团，否则为不在团
        let lastLeave = null,
          i = 0;
        for (; i < leave.length; i++) {
          if (leave[i] > time) {
            lastLeave = leave[i - 1];
            break;
          }
        }
        lastLeave = lastLeave || leave[i - 1];
        // console.log(name,`${new Date(join.find(o=>o>lastLeave&&o<time)).toLocaleTimeString()} - ${new Date(lastLeave).toLocaleTimeString()}`)
        return join.some(o => o > lastLeave && o < time);
      }
    },
    isAttend(name, time) {
      let isAttend = false;
      //判断大号是否存在某个小号(或自己)在指定的时间点在团，注意，传入的必须是大号
      let player = this.dkpObj.playerRelation[name];
      if(player.linkedTo){
        throw new Error('必须传入大号！');
      }

      let isOnLine = this.isOnLine(name, time);
      if(isOnLine){//此号在团
        return true;
      }

      //此乃大号，需查找其他小号是否有在团的
      isAttend = Object.keys(this.dkpObj.players).map(name=>({
        name,
        ...this.dkpObj.playerRelation[name]
      })).filter(p=>p.linkedTo == name).some(p=>this.isOnLine(p.name, time))

      return isAttend;
    },
    commonCmdDone(cmd,type,time) {
      let score = 1;
      let players = this.getActivePlayers(score, time);
      let checkCount = 0, allCount = 0;
      players.forEach(o => {
        checkCount += o.checked;
        allCount += !o.noScore;
      });

      this.dkpRecord[`additional${type}Item`].unshift({
        reason: cmd,
        reasonNote: "",
        score,
        checkAll: allCount == checkCount,
        players
      });
    },
    newAdditional(cmd,type) {
      let map = {
        collect: '集合',
        dismiss: '解散'
      }

      let getScore = function(score, item) {
        let p = item.players.find(p=>p.score>0);
        return score + (p?p.score:0);
      }

      let checkClass = clazz => ['战士','牧师','德鲁伊','萨满祭司'].indexOf(clazz) > -1

      if(['collect','dismiss'].indexOf(cmd)>=0){
        let d;
        if(cmd == 'collect'){
          d = new Date(this.dkpObj.start.replace(/-/g,'/'));
          d.setHours(20);
          d.setMinutes(30);
          d.setSeconds(0);
        }else{
          d = new Date(this.dkpObj.end.replace(/-/g,'/'));
          if(this.dkpObj.bossKills.length > 0){
            d = new Date(this.dkpObj.bossKills[this.dkpObj.bossKills.length-1].time.replace(/-/g,'/'))
          }
        }

        this.$prompt(`请输入${map[cmd]}时间`, '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          inputValue: dateFormat(d),
          inputPattern: /20\d\d-\d\d?-\d\d? \d\d?:\d\d?:\d\d?/,
          inputErrorMessage: `请输入${map[cmd]}时间（如：2018-11-23 20:30:00）`,
          inputPlaceholder: `请输入${map[cmd]}时间（如：2018-11-23 20:30:00）`
        }).then(({ value }) => {
          let score = 1;
          let players = this.getActivePlayers(score, value);
          let duration = new Date(this.dkpObj.end) - new Date(this.dkpObj.start);

          //只有在团时间超过活动时间半数的人，才有集合分和解散分
          players.forEach(o => {
            if(o.noScore) {
              //不需要加分的角色不参与运算
              return;
            }

            //1.找出该角色相关的所有参团角色信息
              //当前角色、当前角色有相同的主号、主号是当前角色、当前角色的主号，都是相关角色
            let relatedPlayers = Object.keys(this.dkpObj.players).filter(p => {
              return p === o.name || 
                (this.dkpObj.playerRelation[o.name].linkedTo && this.dkpObj.playerRelation[o.name].linkedTo === this.dkpObj.playerRelation[p].linkedTo) ||
                this.dkpObj.playerRelation[p].linkedTo === o.name ||
                this.dkpObj.playerRelation[o.name].linkedTo === p
            })

            //2.取出所有角色的在团时间区间，如有重合的，进行合并
              //取出所有角色的在团时间区间
            let ranges = [];

            relatedPlayers.forEach(p => {
              let joins = this.dkpObj.players[p].join.concat();
              let leaves = this.dkpObj.players[p].leave.concat();
              // if(o.name=='四楼楼长'){
              //   console.log(p)
              //   console.log(joins.map(j=>dateFormat(new Date(j))), 'joins')
              //   console.log(leaves.map(l=>dateFormat(new Date(l))), 'leaves')
              // }

              let lastRange = null;
              joins.forEach(join => {
                let leave = leaves.find(t => t > join && (!lastRange || t > lastRange.leave));
                // if(o.name=='四楼楼长'){
                //   console.log(lastRange, 'lastRange')
                //   console.log(dateFormat(new Date(join)), 'join')
                //   console.log(dateFormat(new Date(leave)), 'leave')
                // }

                lastRange = {
                  join,
                  leave
                }

                ranges.push(lastRange)
              })
            })

              //合并去重
            for(let i=0; i<ranges.length-1; i++){
              for(let j=i+1;j<ranges.length;j++){
                let join1 = ranges[i].join,
                    leave1 = ranges[i].leave,
                    join2 = ranges[j].join,
                    leave2 = ranges[j].leave
                //判断一个区间是否和另一个区间有重叠,有以下几种情况:
                if(join2 < join1){
                  if(leave2 >= join1){
                    ranges[i].join = join2
                    if(leave2 > leave1){
                      ranges[i].leave = leave2
                    }
                    ranges.splice(j--,1)                    
                  }
                }else{
                  if(join2 <= leave1){
                    if(leave2 > leave1){
                      ranges[i].leave = leave2
                    }
                    ranges.splice(j--,1)                                  
                  }
                }
              }
            }

            // if(o.name=='四楼楼长'){
              // console.log({
              //   name: o.name,
              //   ranges: ranges.map(r=>({
              //     join: dateFormat(new Date(r.join)),
              //     leave: dateFormat(new Date(r.leave))
              //   }))
              // })
            // }

            //3.根据时间区间计算时长，将所有时长相加，得到参团总时长(单位毫秒)
            let timeTotal = ranges.reduce((last,o)=>last + (o.leave - o.join),0);
            // console.log(timeTotal, o.name)
            //4.将参团时长与活动时长的一半比较，少于一半的，集合和解散分为0
            if(timeTotal < duration / 2){
              o.score = 0;
              o.checked = false;
            }
          });
          // console.log(duration)

          let checkCount = 0, allCount = 0;
          players.forEach(o => {
            checkCount += o.checked;
            allCount += !o.noScore;
          });

          this.dkpRecord[`additional${type}Item`].unshift({
            reason: cmd,
            reasonNote: "",
            score,
            checkAll: allCount == checkCount,
            players
          });
        }).catch((e) => {
          console.log(e)
        });
      } else if(cmd == 'whole') {
        // 查找全程(全部boss击杀都参与)都在的团员

        // 将参团人员进行转换，小号全部转成大号，并去重
        let wholeJourneyPlayers = Array.from(new Set(Object.keys(this.dkpObj.players).map(p => {
          let player = this.dkpObj.playerRelation[p];
          return player.linkedTo || p;
        }))).filter(name=>{
          // 去除有中途不在团的
          return !this.dkpObj.bossKills.some(({time})=>!this.isAttend(name, time))
        }).map(name=>{
          return {
            name,
            class: this.dkpObj.playerRelation[name].class,
            children: Object.keys(this.dkpObj.players).map(o=>{
                        let l = this.dkpObj.playerRelation[o];
                        return {
                          name: o,
                          class: l.class,
                          linkedTo: l.linkedTo
                        }
                      }).filter(o=>o.linkedTo == name)
          }
        }).filter(o=>{
          // 筛选出符合要求的角色
          if(o.children.some(o=>checkClass(o.class))){
            // 本次活动本号的相关小号有上线，并且职业符合要求
            return true;
          }else if(checkClass(o.class) && this.dkpObj.players[o.name]){
            //　本次活动本号有上线并且职业符合要求
            return true;
          }
          return false
        }).map(o=>o.name)

        // console.log(wholeJourneyPlayers)
        let score = 0;
        score = this.dkpRecord.raiseItem.reduce(getScore,0)
        score = this.dkpRecord.additionalRaiseItem.reduce(getScore, score);
        score = parseFloat((score * 0.2).toFixed(2));
        let players = this.getActivePlayers(score);
        let checkCount = 0, allCount = 0;
        players.forEach(p => {
          let isInBonusList = wholeJourneyPlayers.indexOf(p.name)>-1 || wholeJourneyPlayers.indexOf(p.linkedTo)>-1;
          p.checked = isInBonusList && !p.noScore;
          p.score = score * p.checked;
          checkCount += p.checked;
          allCount += !p.noScore;
        })
        players.sort((a, b) => b.checked - a.checked);

        this.dkpRecord[`additional${type}Item`].unshift({
          reason: cmd,
          reasonNote: "",
          score,
          checkAll: allCount == checkCount,
          players
        });
      } else {
        this.commonCmdDone(cmd,type);
      }
    },
    removeRow(row,type) {
      this.$confirm(`确定要删除这条${{Raise:'加',Down:'扣'}[type]}分项吗？`, "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      }).then(() => {
        this.dkpRecord[`additional${type}Item`].splice(
          this.dkpRecord[`additional${type}Item`].indexOf(row),
          1
        );
      });
    }
  }
};
</script>

<style lang="less" scoped>
.players-wrapper {
  background: rgba(0, 0, 0, 0.7);
  display: flex;
  flex-wrap: wrap;
  &.with-checkbox > span {
    width: 210px;
    white-space: nowrap;
  }
  > span {
    font-size: 12px;
    width: 180px;
    padding: 2px 5px;
    .player-name {
      display: inline-block;
      width: 80px;
      text-align: right;
      padding-right: 4px;
      box-sizing: border-box;
    }
  }
}
.score-input {
  width: 95px !important;
}
</style>

<style lang="less">
.wrapper{
  .el-checkbox{
    margin-right: 5px;
  }
}
</style>